//Copyright (c) 2012, peter.ducai@gmail.com
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following 
//conditions are met:
//
//Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
//in the documentation and/or other materials provided with the distribution.
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
//OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
//OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
//OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
//OF SUCH DAMAGE.

package com.daemonna.fluentlee_core.readers;

import com.daemonna.fluentlee_core.objects.connector;
import com.daemonna.fluentlee_core.pools.connector_pool;
import com.daemonna.fluentlee_core.pools.data_pool;
import com.daemonna.fluentlee_core.pools.server_settings_pool;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/*
 * @author peter 'daemonna' ducai
 * @author peter.ducai@gmail.com 
 * @author http://code.google.com/p/fluentlee/
 */
public class settings_reader {

    DocumentBuilderFactory domFactory = null;
    DocumentBuilder builder = null;
    XPathFactory factory = null;
    Document doc = null;
    XPath xpath = null;

    /**
     * Create xml reader and disable dtd/schema
     */
    public settings_reader() throws ParserConfigurationException, SAXException, IOException {

        domFactory = DocumentBuilderFactory.newInstance();
        domFactory.setNamespaceAware(true); // never forget this!
        domFactory.setValidating(false);

        try {
            domFactory.setFeature("http://xml.org/sax/features/validation", false);
            domFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
            domFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            domFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
            domFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        } catch (Exception e1) {
            Logger.getLogger(settings_reader.class.getName()).log(Level.SEVERE, null, e1);
        }
        
        builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        doc = builder.parse("settings/settings.xml");
        factory = XPathFactory.newInstance();
        xpath = factory.newXPath();

    }

    /**
     * read settings.xml and load all global_val into data_pool
     */
    public void load_global_values() throws ParserConfigurationException, SAXException, XPathExpressionException, IOException {

        XPathExpression expr = xpath.compile("//settings/global_val");
        Object result = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList node = (NodeList) result;

        System.out.println("GLOBALS: " + node.getLength());

        for (int i = 0; i < node.getLength(); i++) {

            String globname = node.item(i).getAttributes().getNamedItem("name").getTextContent();
            String globval = node.item(i).getTextContent();
            data_pool.getInstance().globals.put(globname, globval);

        }
    }
    
    /**
     * read settings.xml and load all server related settings (IP, port)
     */
    public void load_server_settings() throws ParserConfigurationException, SAXException, XPathExpressionException, IOException {

        //read settings for docs/http server
        XPathExpression expr = xpath.compile("//settings/server/doc_server");
        Object result = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList node = (NodeList) result;

        for (int i = 0; i < node.getLength(); i++) {

            server_settings_pool.getInstance().docserv_listen_address = node.item(i).getAttributes().getNamedItem("address").toString();
            server_settings_pool.getInstance().docserv_listen_port = Integer.getInteger(node.item(i).getAttributes().getNamedItem("port").toString());
            server_settings_pool.getInstance().docserv_max_connections = Integer.getInteger(node.item(i).getAttributes().getNamedItem("max_connections=").toString());
        }
        
        //read settings for job server
        expr = xpath.compile("//settings/server/job_server");
        result = expr.evaluate(doc, XPathConstants.NODESET);
        node = (NodeList) result;

        for (int i = 0; i < node.getLength(); i++) {

            server_settings_pool.getInstance().jobserv_listen_address = node.item(i).getAttributes().getNamedItem("address").toString();
            server_settings_pool.getInstance().jobserv_listen_port = Integer.getInteger(node.item(i).getAttributes().getNamedItem("port").toString());
            server_settings_pool.getInstance().jobserv_max_connections = Integer.getInteger(node.item(i).getAttributes().getNamedItem("max_connections=").toString());
        
        }
    }
    
    /**
     * read settings.xml and load all global_val into data_pool
     */
    public void load_connectors() throws ParserConfigurationException, SAXException, XPathExpressionException, IOException, Exception {

        XPathExpression expr = xpath.compile("//settings/db_connector");
        Object result = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList node = (NodeList) result;

        System.out.println("CONNECTORS: " + node.getLength());

        for (int i = 0; i < node.getLength(); i++) {

            String connname = node.item(i).getAttributes().getNamedItem("name").getTextContent();
            String conntype = node.item(i).getAttributes().getNamedItem("type").getTextContent();
            String connurl = node.item(i).getAttributes().getNamedItem("url").getTextContent();
            System.out.println("type found: "+conntype);
            
            //derby and sqlite doesnt require user and password!
            if((!"sqlite".equals(conntype)) && (!"derby".equals(conntype))){
                String connuser = node.item(i).getAttributes().getNamedItem("user").getTextContent();
                String connpassw = node.item(i).getAttributes().getNamedItem("password").getTextContent();
                
                //create new connector and add it to global connector array + add user and password
                connector_pool.getInstance().conns[i] = new connector();
                connector_pool.getInstance().conn_count++;
                connector_pool.getInstance().conns[i].id = i;
                connector_pool.getInstance().conns[i].user = connuser;
                connector_pool.getInstance().conns[i].password = connpassw;
                connector_pool.getInstance().conns[i].url = connurl;
                connector_pool.getInstance().conns[i].name = connname;
                
                //set type and format url
                switch (conntype) {
                    case "oracle":
                        connector_pool.getInstance().conns[i].conn_type = connector.type.ORACLE;
                        break;
                    case "mysql":
                        connector_pool.getInstance().conns[i].conn_type = connector.type.MYSQL;
                        break; 
                    case "postgres":
                        connector_pool.getInstance().conns[i].conn_type = connector.type.POSTGRES;
                        break;
                }
                connector_pool.getInstance().conns[i].format_url_by_type();
                
            } else {
                //create new connector and add it to global connector array
                connector_pool.getInstance().conns[i] = new connector();
                connector_pool.getInstance().conn_count++;
                connector_pool.getInstance().conns[i].id = i;
                 connector_pool.getInstance().conns[i].url = connurl;
                connector_pool.getInstance().conns[i].name = connname;
                //set type and format url
                switch (conntype) {
                    case "derby":
                        connector_pool.getInstance().conns[i].conn_type = connector.type.DERBY;
                        break;
                    case "sqlite":
                        connector_pool.getInstance().conns[i].conn_type = connector.type.SQLITE;
                        break;
                }
                connector_pool.getInstance().conns[i].format_url_by_type();
            }   
        }
    }

    /**
     * load all aliases and sort out types of them
     */
    public void load_aliases() throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {

        XPathExpression expr = xpath.compile("//settings/alias");
        Object result = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList node = (NodeList) result;

        System.out.println("ALIASES: " + node.getLength());

        for (int i = 0; i < node.getLength(); i++) {

            String aname = node.item(i).getAttributes().getNamedItem("name").getTextContent();
            String atype = node.item(i).getAttributes().getNamedItem("type").getTextContent();
            String formated = construct_alias(aname, atype);

            data_pool.getInstance().aliases.put(aname, formated);
            System.out.println("construct alias: " + formated);
        }
    }

    /**
     * create aliases and set type
     *
     * @param alias_name name of alias
     * @param type type of alias, options are posix, gnu, shell, java, oracle,
     * postgres, mysql, sqlite, jdbc, berkleydb, hadoop and riak
     */
    public String construct_alias(String alias_name, String type) throws ParserConfigurationException, SAXException, XPathExpressionException, IOException {
        String alias = "";
        String[] strings = new String[500];

        XPathExpression expr = xpath.compile("//settings/alias[@name='" + alias_name + "']/value");
        Object result = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList node = (NodeList) result;

        //put all values in array
        for (int i = 0; i < node.getLength(); i++) {

            String gkey = node.item(i).getAttributes().getNamedItem("name").getTextContent();
            String gval = node.item(i).getTextContent();
            //format values depending on type
            switch (type) {
                case "posix":
                    //POSIX like options (ie. tar -zxvf foo.tar.gz)
                    alias = alias + " -" + gkey + " " + gval + " ";
                    break;
                case "gnu":
                    //GNU like long options (ie. du --human -readable --max-depth=1)
                    alias = alias + " --" + gkey + " " + gval + " ";
                    break;
                case "shell":
                    //$property=value   ...all values defined by $
                    alias = alias + " $" + gkey + "=" + gval + " ";
                    break;
                case "java":
                    //Java like properties (ie. java -Djava.awt.headless=true -Djava.net.useSystemProxies=true Foo)
                    alias = alias + " -D" + gkey + "=" + gval + " ";
                    break;
                case "oracle":
                    break;
                case "mysql":
                    break;
                case "postgres":
                    break;
                case "sqlite":
                    break;
                case "jdbc":
                    break;
                case "berkleydb":
                    break;
                case "hadoop":
                    break;
                case "riak":
                    break;
                case "robot":
                    //--variable DB_HOST:dbservername --variable DATABASE_SID:some_SID
                    alias = alias + " --variable " + gkey + ":" + gval + " ";
                    break;
            }
        }

        return alias;
    }
}
